﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using CsvHelper.TypeConversion;
using HtmlAgilityPack;
using CsvHelper.Configuration;

namespace BitworkStudios.Scraper.Document
{
    public class Element
    {
        [CsvField(Name = "Label", Index = 0)]
        public string Label { get; set; }

        [CsvField(Name = "Node Path", Index = 1)]
        public string NodePath { get; set; }

        [CsvField(Name = "Node Type", Index = 2)]
        public NodeType Type { get; set; }

        [CsvField(Ignore = true)]
        public string Value { get; set; }

        public void GetNode(HtmlDocument htmlDocument)
        {
            HtmlNode node = htmlDocument.DocumentNode.SelectSingleNode(NodePath);

            switch (Type)
            {
                case NodeType.InnerText:
                    Value = node.InnerText;
                    break;
                case NodeType.InnerHtml:
                    Value = node.InnerHtml;
                    break;
                case NodeType.Link:
                    Value = node.Attributes["href"].Value;
                    break;
                default:
                    Value = node.InnerText;
                    break;
            }

            Value = Value.Trim(' ', '\n');
        }

        public static List<Element> GetTemplate<T>()
        {
            var templateElements = new List<Element>();
            PropertyInfo[] propertiesList = typeof(T).GetProperties();

            foreach (PropertyInfo propertyInfo in propertiesList)
            {
                var propertyAttribute = propertyInfo.GetCustomAttribute<ElementDefinitionAttribute>();

                if (!propertyAttribute.Ignore)
                {
                    string nodeLabel = propertyInfo.Name;
                    string nodePath = @"\\";
                    NodeType propertyType = propertyAttribute.Type;

                    if (!String.IsNullOrEmpty(propertyAttribute.Label))
                    {
                        nodeLabel = propertyAttribute.Label;
                    }

                    if (!String.IsNullOrEmpty(propertyAttribute.NodePath))
                    {
                        nodePath = propertyAttribute.NodePath;
                    }

                    var elementTemplate = new Element
                                              {
                                                  Label = nodeLabel,
                                                  NodePath = nodePath,
                                                  Type = propertyType
                                              };

                    templateElements.Add(elementTemplate);
                }
            }

            return templateElements;
        }

        public static T GetTInstance<T>(List<Element> elements) where T : new()
        {
            var tInstance = new T();
            PropertyInfo[] tProperties = tInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo propertyInfo in tProperties)
            {
                foreach (Element element in elements)
                {
                    if(String.CompareOrdinal(element.Label, propertyInfo.Name) == 0)
                    {
                        propertyInfo.SetValue(tInstance, element.Value);
                        break;
                    }
                }
            }

            return tInstance;
        }
    }
}
